package com.yhxd.modular.reference.service;

import com.querydsl.jpa.impl.JPAQueryFactory;
import com.yhxd.modular.reference.dao.DirectoryDao;
import com.yhxd.modular.reference.dao.PublicFileDao;
import com.yhxd.modular.reference.entity.Directory;
import com.yhxd.modular.reference.entity.PublicFile;
import com.yhxd.modular.reference.entity.QDirectory;
import com.yhxd.modular.reference.entity.QPublicFile;
import com.yhxd.modular.system.entity.Config;
import com.yhxd.modular.system.entity.User;
import com.yhxd.utils.RedissonUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class DirectoryService {

    @Autowired
    private JPAQueryFactory factory;

    @Autowired
    private DirectoryDao directoryDao;

    @Autowired
    private PublicFileDao publicFileDao;

    public List<Directory> findAll() {
        return this.directoryDao.findAll(Sort.by(Sort.Direction.ASC, "id"));
    }

    /**
     * 删除目录
     * @param ids
     */
    @Transactional(rollbackFor = Exception.class)
    public void delDir(String ids) throws IOException {
        QPublicFile qPublicFile = QPublicFile.publicFile;
        QDirectory qDirectory = QDirectory.directory;

        String []idArray = ids.split(",");
        List<Long> idList = Arrays.asList(idArray).stream().map(id -> Long.parseLong(id)).collect(Collectors.toList());
        List<Directory> directoryList = this.directoryDao.findByIdIn(idList);

        Map<String, Config> configMap = (Map<String, Config>) RedissonUtils.getObject("config");
        String basePath = configMap.get("upload_mng").getConfValue();

        //删除数据库文件表
        this.factory
                .delete(qPublicFile)
                .where(qPublicFile.dirId.in(idList))
                .execute();
        //删除数据库目录表
        this.factory
                .delete(qDirectory)
                .where(qDirectory.id.in(idList))
                .execute();

        //删除物理文件
        for (Directory directory : directoryList) {
            String path = (basePath + directory.getDirPath() + directory.getDirName()).replaceAll("//", "/");;
            File file = new File(path);
            FileUtils.deleteDirectory(file);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void editDir(Long id, String newName) throws Exception {
        User shiroUser = (User) SecurityUtils.getSubject().getPrincipals().getPrimaryPrincipal();
        Directory directory = this.directoryDao.findById(id).orElse(null);

        //校验当前路径是否存在同名目录
        if (null != directory) {
            Directory dir = this.directoryDao.findByDirNameAndDirPath(newName, directory.getDirPath());
            if (null == dir) {
                String oldPath = (directory.getDirPath() + directory.getDirName()).replace("//", "/");
                String newPath = (directory.getDirPath() + newName).replace("//", "/");

                //修改当前目录
                directory.setDirName(newName);
                directory.setUpdateName(shiroUser.getRealName());
                this.directoryDao.save(directory);

                //修改所有子目录的路径
                List<Directory> childDirList = this.directoryDao.findByIdNotAndDirPathLike(id, "%" + oldPath + "%");
                if (CollectionUtils.isNotEmpty(childDirList)) {
                    for (Directory childDir : childDirList) {
                        childDir.setDirPath(childDir.getDirPath().replace(oldPath, newPath));
                        this.directoryDao.save(childDir);
                    }
                }

                //修改所有相关文件的路径
                List<PublicFile> childFileList = this.publicFileDao.findByPathLike("%" + oldPath + "%");
                if (CollectionUtils.isNotEmpty(childFileList)) {
                    for (PublicFile childFile : childFileList) {
                        childFile.setPath(childFile.getPath().replace(oldPath, newPath));
                        this.publicFileDao.save(childFile);
                    }
                }

                //修改硬盘目录文件名
                Map<String, Config> configMap = (Map<String, Config>) RedissonUtils.getObject("config");
                String basePath = configMap.get("upload_mng").getConfValue();
                String oldDirPath = (basePath + oldPath).replaceAll("//", "/");
                String newDirPath = (basePath + newPath).replaceAll("//", "/");
                FileUtils.moveDirectory(new File(oldDirPath), new File(newDirPath));
            } else {
                throw new RuntimeException("该路径已存在同名目录");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Directory addDir(Long id, String childName) throws Exception {
        User shiroUser = (User) SecurityUtils.getSubject().getPrincipals().getPrimaryPrincipal();
        List<Directory> directoryList = this.directoryDao.findByPidAndDirName(id, childName);

        //校验当前路径是否存在同名目录
        if (CollectionUtils.isEmpty(directoryList)) {
            Directory parentDir = null;
            if (0 == id) {
                parentDir = new Directory();
                parentDir.setId(0L);
                parentDir.setDirPath("");
                parentDir.setDirName("");
            } else {
                parentDir = this.directoryDao.findById(id).orElse(null);
            }
            Directory newDir = new Directory();
            newDir.setDirName(childName);
            newDir.setDirPath(parentDir.getDirPath() + parentDir.getDirName() + "/");
            newDir.setPid(parentDir.getId());
            newDir.setCreateName(shiroUser.getRealName());
            newDir.setUpdateName(shiroUser.getRealName());
            this.directoryDao.save(newDir);

            //创建硬盘目录
            Map<String, Config> configMap = (Map<String, Config>) RedissonUtils.getObject("config");
            String basePath = configMap.get("upload_mng").getConfValue();
            String dirPath = (basePath + newDir.getDirPath() + newDir.getDirName()).replaceAll("//", "/");
            FileUtils.forceMkdir(new File(dirPath));
            return newDir;
        } else {
            throw new RuntimeException("该目录下已存在同名目录");
        }
    }
}
